home *** CD-ROM | disk | FTP | other *** search
/ Windows Expert / Windows Expert.iso / windownt / sossnt.zip / SOSSNT / SRC / INODES.C < prev    next >
C/C++ Source or Header  |  1993-03-03  |  20KB  |  741 lines

  1. /*
  2.  *  inodes.c --
  3.  *      Index node implementation for PC NFS file server.  The server
  4.  *      builds its view of the filesystem everytime a lookup call is
  5.  *      generated for a file, and initially when the file system export
  6.  *      list is parsed.  This package handles DOS and UNIX style pathnames.
  7.  *
  8.  *  Author:
  9.  *      See-Mong Tan
  10.  *  Modified by:
  11.  *    Rich Braun @ Kronos
  12.  */
  13.  
  14. #include "common.h"
  15.  
  16. /* forward declaration of local procedures */
  17. static void getcomp();
  18. static u_long insertapath();
  19. static u_long newinodeno();
  20. static bool_t _inremnode();
  21.  
  22. /* the inode dump file */
  23. #define INODEFILE "inode.dmp"
  24.  
  25. /* Number of inodes and attributes entries to store in memory */
  26. #define NUMINODES 64000
  27. #define NUMACACHE 400
  28.  
  29. /* the global inode file pointer */
  30. static FILE *inodefp;
  31.  
  32. /* last inode number assigned - starting from 2, 1 is root directory of all */
  33. static u_long lastinodeno = 2;
  34.  
  35.   /* The attributes cache.  Each inode is optionally associated        */
  36.   /* with a cache entry containing its file attributes (owner UID,    */
  37.   /* size, creation date, etc.)  The cache is fixed in size and is      */
  38.   /* stored in the form of a doubly-linked list, with the most recently */
  39.   /* accessed item at the head and the oldest at the tail.  If the      */
  40.   /* cache is full, the oldest item is disassociated with its inode     */
  41.   /* and it is moved to the had and associated with a new inode.        */
  42.  
  43. typedef struct _acache {
  44.     struct _acache *next;
  45.     struct _acache *prev;
  46.     u_short             inode;
  47.     struct nfsfattr     fattr;
  48. } Acache_t;
  49.  
  50. static Acache_t *attrcache;        /* Head and tail pointers */
  51. static Acache_t *attrfree;
  52.  
  53.   /* The inode cache. */
  54. typedef struct DIRNODE {
  55.     char name[MAXFILENAMELEN];    /* dos file name */
  56.     u_char  fsid;            /* drive of file (1 = A:) */
  57.     u_short inode;            /* its inode number */
  58.     u_short    top : 1,        /* Flag indicating top of filesystem*/
  59.         gen : 14;        /* generation count */
  60.     struct DIRNODE *next;    /* next file in same directory */
  61.     struct DIRNODE *subdir;    /* ptr to subdirectory entries */
  62.     struct DIRNODE *parent;    /* ptr to parent directory */
  63.     Acache_t *attr;        /* file attributes, if known */
  64. } Dir_t;
  65.  
  66.   /* the directory structure begins here */
  67. static Dir_t *RootDir = NULL;
  68.  
  69.   /* the inode table - list of directory node pointers  */
  70.   /* allocated on initialization            */
  71. typedef Dir_t *Inode_t;
  72.  
  73. Inode_t *InodeTable;
  74. static u_short gencount = 1;
  75.  
  76. /*
  77.  *  bool_t inode_init() --
  78.  *      Initializes the inode module.  Reads the previous (if any) inodes
  79.  *      created and adds them to the directory tree.  Has a very simple
  80.  *      minded export file parser.
  81.  */
  82. bool_t inode_init()
  83. {
  84.     FILE *fp;
  85.     char line[300];
  86.     char path[MAXPATHNAMELEN];
  87.     int i;
  88.  
  89.     /* Initialize inode table */
  90.  
  91.     if ((InodeTable = (Inode_t *) malloc (NUMINODES * 4)) == NULL)
  92.       return FALSE;
  93.  
  94.     /* Initialize attributes cache */
  95.  
  96.     if ((attrcache = (Acache_t *) malloc (NUMACACHE *
  97.                     sizeof (Acache_t))) == NULL)
  98.       return FALSE;
  99.  
  100.     /* The 0th entry is the list head; the free list starts at  */
  101.     /* entry 1.                            */
  102.     attrcache->next = attrcache->prev = attrcache;
  103.     attrcache->inode = 0;
  104.     attrfree = &attrcache[1];
  105.  
  106.     for (i = 0; i < NUMACACHE-2; i++)
  107.     attrfree[i].next = &attrfree[i+1];
  108.     attrfree[i].next = NULL;
  109.  
  110.     /* Read export list to build initial inode tree */
  111.     if ((fp = fopen(EXPORTS, "r")) == NULL)
  112.       return FALSE;
  113.     while(fgets(line, MAXPATHNAMELEN -1, fp) == line) {
  114.     u_long nodeid;
  115.  
  116.     /* get the pathname alone */
  117.     sscanf (line, "%s", path);
  118.  
  119.     /* Truncate trailing backslash for root directory */
  120.     if (path[1] == ':' && path[3] == '\0')
  121.       path[2] = '\0';
  122.  
  123.     /* Skip if shorter than 2 characters */
  124.     if (strlen(path) < 2) 
  125.       break;
  126.  
  127.     nodeid = insertapath(path, (Dir_t *) NULL,
  128.                  (Dir_t **) &RootDir);
  129.  
  130.     /* Set the top-of-filesystem flag */
  131.     InodeTable[nodeid]->top = TRUE;
  132.     }
  133.     (void) fclose(fp);
  134.  
  135.     /* rebuild old filesystem tree */
  136.     /* open for reading and appending */
  137.     if ((fp = fopen(INODEFILE, "a+")) == NULL)
  138.       return FALSE;
  139.  
  140.     while(fscanf(fp, "%s", path) != EOF) {
  141.     if (path[0] != '-')
  142.       (void) insertapath(path, (Dir_t *) NULL,
  143.                  (Dir_t **) &RootDir);
  144.     else {
  145.         u_long nodeid;
  146.  
  147.         sscanf (path+1, "%ld", &nodeid);
  148.         (void) _inremnode (nodeid);
  149.     }
  150.     }
  151.     (void) fclose(fp);
  152.     return TRUE;
  153. }
  154.  
  155. /*        
  156.  *  void getcomp(char *comp, char **path) --
  157.  *      Gets component name of *path and puts it in comp, and advances
  158.  *      *path to beginning of next component.  Handles UNIX or DOS style
  159.  *      pathnames.
  160.  */
  161. /* Valid characters in a DOS name are:  ! #$%&'() -. @ ^_` {}~ */
  162.  
  163. u_char inchvalid[95] = {   1, 0, 1, 1, 1, 1, 1,       /* ! thru ' */
  164.             1, 1, 0, 0, 0, 1, 1, 0,     /* ( thru / */
  165.             1, 1, 1, 1, 1, 1, 1, 1,        /* 0 thru 7 */
  166.             1, 1, 0, 0, 0, 0, 0, 0,        /* 8 thru ? */
  167.             1, 1, 1, 1, 1, 1, 1, 1,        /* @ thru G */
  168.             1, 1, 1, 1, 1, 1, 1, 1,        /* H thru O */
  169.             1, 1, 1, 1, 1, 1, 1, 1,        /* P thru W */
  170.             1, 1, 1, 0, 0, 0, 1, 1,        /* X thru _ */
  171.             1, 1, 1, 1, 1, 1, 1, 1,        /* ` thru g */
  172.             1, 1, 1, 1, 1, 1, 1, 1,        /* h thru o */
  173.             1, 1, 1, 1, 1, 1, 1, 1,        /* p thru w */
  174.             1, 1, 1, 1, 0, 1, 1, 0};    /* x thru DEL */
  175.  
  176. static void getcomp(comp, path)
  177.      char *comp;
  178.      char **path;
  179. {
  180.     if (! (**path > ' ' && !(**path & 0x80) && inchvalid[**path - '!']))
  181.       (*path)++;
  182.     while(**path > ' ' && !(**path & 0x80) && inchvalid[**path - '!']) {
  183.     *comp++ = **path;
  184.     (*path)++;
  185.     }
  186.     if (**path == ':')
  187.       (*path)++;
  188.     *comp = '\0';
  189. }
  190.  
  191. /*
  192.  *  Dir_t *makenewdirnode(char *name, Dir_t *parent) --
  193.  *      Returns new directory node initialized with name.
  194.  */
  195. Dir_t *makenewdirnode(name, parent)
  196.      char *name;
  197.      Dir_t *parent;
  198. {
  199.     Dir_t *new;
  200.  
  201.     new = (Dir_t *) malloc(sizeof(Dir_t));
  202.     if (new == (Dir_t *) NULL) {
  203.     (void) fprintf(stderr, "nfs: out of memory\n");
  204.     abort();
  205.     }
  206.     (void) bcopy_nf(name, new->name, MAXFILENAMELEN);
  207.     new->inode = (u_short) newinodeno();
  208.     new->parent = parent;
  209.     new->next = new->subdir = (Dir_t *) NULL;
  210.     new->attr = NULL;
  211.     new->top  = FALSE;
  212.     new->gen  = gencount++;
  213.     if (parent == (Dir_t *) NULL)
  214.       new->fsid = *name - (islower(*name) ? 'a' : 'A') + 1;
  215.     else
  216.       new->fsid = parent->fsid;
  217.     InodeTable[new->inode] = new;
  218.     return new;
  219. }
  220.  
  221. /*
  222.  *  void inremnode(u_long inode) --
  223.  *      Removes the indicated node.
  224.  */
  225. void inremnode (inode)
  226.      u_long inode;
  227. {
  228.     if (_inremnode (inode)) {
  229.     if (inodefp == (FILE *) NULL)
  230.       inodefp = fopen(INODEFILE, "a");
  231.     (void) fprintf(inodefp, "-%ld\n", inode);    /* add to inode file */
  232.     }
  233. /*   else {
  234.  *    DBGPRT1 (nfserr, "inremnode %ld failed", inode);
  235.  *  }
  236.  */
  237. }
  238.  
  239. /*
  240.  *  bool_t _inremnode(u_long inode) --
  241.  *      Prunes an inode from the tree.
  242.  */
  243. static bool_t _inremnode (inode)
  244.      u_long inode;
  245. {
  246.     Dir_t *dirp, *p, *q;
  247.  
  248.     if (inode > NUMINODES || (dirp = InodeTable[inode]) == (Dir_t *) NULL)
  249.       return FALSE;
  250.  
  251.     if (dirp->subdir != (Dir_t *) NULL)
  252.       return FALSE;
  253.  
  254.     /* If this is the first node in the list, simply point the parent   */
  255.     /* to the next item.                        */
  256.     if (dirp->parent->subdir->inode == (u_short) inode) {
  257.     dirp->parent->subdir = dirp->next;
  258.     }
  259.     else {
  260.     /* Scan the list looking for inode */
  261.     p = dirp->parent->subdir->next;  q = dirp->parent->subdir;
  262.     while(p != (Dir_t *) NULL && p->inode != (u_short) inode) {
  263.         q = p; p = p->next;
  264.     }
  265.     /* Unlink this node from the list */
  266.     if (p == (Dir_t *) NULL)
  267.         return FALSE;
  268.     q->next = p->next;
  269.     }
  270.  
  271.     /* Free up the memory used by this inode and its attributes */
  272.     if (dirp->attr != (Acache_t *) NULL) {
  273.     dirp->attr->prev->next = dirp->attr->next;
  274.     dirp->attr->next->prev = dirp->attr->prev;
  275.     dirp->attr->next = attrfree;
  276.     attrfree = dirp->attr;
  277.     }
  278.     (void) free (dirp);
  279.     return TRUE;
  280. }
  281.  
  282. /*
  283.  *  Dir_t *findindirlist(name, Dir_t *parent, Dir_t **dirlist) --
  284.  *      Finds the node with name in dirlist and returns a ptr to it, or makes
  285.  *      a new node if none is found, and returns a pointer to the new node.
  286.  */
  287. Dir_t *findindirlist(name, parent, dirlist)
  288.     char *name;
  289.     Dir_t *parent;
  290.     Dir_t **dirlist;
  291. {
  292.     int lexico;        /* lexicographic comparator */
  293.     Dir_t *new;
  294.     Dir_t *p;
  295.     Dir_t *q;        /* for inserting down the list */
  296.     char str[MAXFILENAMELEN];
  297.  
  298.     if (*dirlist == (Dir_t *) NULL) {          /* NULL entry */
  299.     *dirlist = makenewdirnode(name, parent);
  300.  
  301.     return *dirlist;
  302.     }
  303.  
  304.     bcopy_fn((*dirlist)->name, str, MAXFILENAMELEN);
  305.     if ((lexico = strcmp(name, str)) < 0) {
  306.     Dir_t *tmp;
  307.  
  308.     /* must insert in front */
  309.  
  310.     new = makenewdirnode(name, parent);
  311.     tmp = *dirlist;
  312.     *dirlist = new;
  313.     new->next = tmp;
  314.  
  315.     return new;
  316.     }
  317.     else if (lexico == 0)             /* found the node */
  318.       return *dirlist;
  319.  
  320.     /* cdr down the list and find node or find place to insert */
  321.     p = (*dirlist)->next;  q = *dirlist;
  322.     while(p != (Dir_t *) NULL) {
  323.     bcopy_fn((p)->name, str, MAXFILENAMELEN);
  324.     if ((lexico = strcmp(name, str)) == 0)
  325.       return p;        /* found it */
  326.     else if (lexico < 0)
  327.       break;            /* should insert here */
  328.     q = p; p = p->next;        /* go on to next elt */
  329.     }
  330.     /* this is where we insert */
  331.     new = makenewdirnode(name, parent);
  332.     q->next = new;
  333.     new->next = p;
  334.  
  335.     return new;
  336. }
  337.  
  338. /*
  339.  *  u_long insertapath(char *path, Dir_t *parent, Dir_t **dirlist) 
  340.  *      Inserts path into dirlist and returns final inode number.
  341.  */
  342. static u_long insertapath(path, parent, dirlist)
  343.      char *path;
  344.      Dir_t *parent;
  345.      Dir_t **dirlist;
  346. {
  347.     char comp[MAXFILENAMELEN];        /* 11 is max length of one component */
  348.     Dir_t *compnode;    /* the component node */
  349.  
  350.     getcomp(comp, &path);                /* get component */
  351.     compnode = findindirlist(comp, parent, (Dir_t **) dirlist);
  352.     if (*path == '\0') {
  353.     return (u_long) compnode->inode;    /* no more descents needed */
  354.     } else
  355.       return insertapath(path, compnode, (Dir_t **) &
  356.              (compnode->subdir));
  357. }
  358.  
  359. /*
  360.  *  u_long addpathtodirtree(char *path) --
  361.  *      Adds a path to the directory tree and return it's inode number.
  362.  */
  363. u_long addpathtodirtree(path)
  364.     char *path;
  365. {
  366.     u_long inode;
  367.  
  368.     if (inodefp == (FILE *) NULL)
  369.       inodefp = fopen(INODEFILE, "a");
  370.     (void) fprintf(inodefp, "%s\n", path);    /* add to inode file */
  371.     return insertapath(path, (Dir_t *) NULL, (Dir_t **) &RootDir);
  372.  
  373.     return inode;
  374. }
  375.  
  376. /*
  377.  *  u_long ingetentry (u_long inode, u_long offset, char *name) --
  378.  *      Finds the node at a given offset in dirlist and returns
  379.  *    its name.  Returns -1 if the node is invalid or the offset
  380.  *    is too large.
  381.  */
  382. long ingetentry (inode, offset, name)
  383.      u_long inode;
  384.      u_long offset;
  385.      char   *name;
  386. {
  387.     Dir_t *p, *q;        /* for scanning the list */
  388. u_long x = offset;
  389.  
  390.     if (inode > NUMINODES || InodeTable[inode] == (Dir_t *) NULL)
  391.       return -1;
  392.  
  393.     /* Handle first two entries specially. */
  394.     if (offset == 0) {
  395.     strcpy (name, ".");
  396.     return inode;
  397.     }
  398.     else if (offset == 1) {
  399.     strcpy (name, "..");
  400.     return InodeTable[inode]->top ? inode :
  401.       InodeTable[inode]->parent->inode;
  402.     }
  403.     offset -= 2;
  404.  
  405.     if ((q = InodeTable[inode]->subdir) == NULL)
  406.       return -1;
  407.     p = q->next;
  408.  
  409.     /* cdr down the list */
  410.     while (offset--) {
  411.     if (p != (Dir_t *) NULL) {
  412.         q = p; p = p->next;        /* go on to next elt */
  413.     }
  414.     else
  415.       return -1;
  416.     }
  417.     bcopy_fn (q->name, name, MAXFILENAMELEN);
  418. /*    DBGPRT3 (inode, "%ld offs %ld %s", inode, x, name); */
  419.     return (u_long) q->inode;
  420. }
  421.  
  422. #if INODE_DEBUG
  423. /*
  424.  *  void shownode(Dir_t *dirt) --
  425.  *      Debugging aid.  Dumps the node.
  426.  */
  427. static void shownode(dirt)
  428.     Dir_t *dirt;
  429. {
  430.     (void) printf("Name: %s;\t Inode #: %d\n", dirt->name, dirt->inode);
  431. }
  432.  
  433. /*
  434.  *  void showtree(Dir_t *dirt) --
  435.  *      Debugging aid.  Dumps the tree.
  436.  */
  437. void showtree(dirt)
  438.     Dir_t *dirt;
  439. {
  440.     while(dirt != (Dir_t *) NULL) {
  441.     shownode(dirt);
  442.     if (dirt->subdir != (Dir_t *) NULL) {
  443.         (void) printf("And in this directory... \n");
  444.         showtree(dirt->subdir);
  445.     }
  446.     dirt = dirt->next;
  447.     }
  448. }
  449. #endif /* INODE_DEBUG */
  450.  
  451. /*
  452.  *  u_long pntoin(char *path) --
  453.  *      Returns inode number corresponding to path.  Path should already
  454.  *      exist.  Returns -1 for error.
  455.  */
  456. #define isdot(path, len) (*((path) + (len) -1) == '.')
  457. #define isdotdot(path, len) (isdot(path,len) && (*((path) + (len) - 2)) == '.')
  458. long pntoin(path)
  459.     char *path;
  460. {
  461.     char comp[MAXFILENAMELEN];        /* component of filename */
  462.     Dir_t *p;
  463.     int len;
  464.     char str[MAXFILENAMELEN];
  465.  
  466.     len = strlen(path);
  467.     if (isdotdot(path, len))
  468.       *(path + len -3) = '\0';
  469.     else if (isdot(path, len))
  470.       *(path + len -2) = '\0';
  471.     
  472.     p = RootDir;            /* start search from root */
  473.     while(p != (Dir_t *) NULL) {        /* search down the tree */
  474.     int lex;
  475.  
  476.     getcomp(comp, &path);        /* search across the tree */
  477.     while(p != (Dir_t *) NULL) {
  478.         bcopy_fn((p)->name, str, MAXFILENAMELEN);
  479.         if ((lex = strcmp(comp, str)) == 0)
  480.           break;
  481.         else if (lex < 0)    /* overshot - not found */
  482.           return -1;
  483.         p = p->next;    /* across on this level */
  484.     }
  485.     if (p == (Dir_t *) NULL)
  486.       return -1;
  487.     else if (*path == '\0') 
  488.       return (u_long) p->inode;
  489.     else
  490.       p = p->subdir;        /* down one level */
  491.     }
  492.     return -1;
  493. }
  494.  
  495. /*
  496.  *  char *intopn(u_long inode, char *path) --
  497.  *      Converts inode to path name in dos format.  DOS style path name
  498.  *    is returned.  A NULL is returned if there is no such inode.
  499.  */
  500. char *intopn(inode, path)
  501.      u_long inode;
  502.      char *path;
  503. {
  504.     Dir_t *dirp;
  505.     char  *ptr;
  506.     u_short stack[30];    /* room for 30 nested directories */
  507.     u_short *stackptr;
  508.  
  509.     if ((dirp = InodeTable[inode]) == (Dir_t *) NULL)
  510.       return NULL;
  511.  
  512.     /* move upwards and set parents to point to this child */
  513.     stackptr = stack;
  514.     while(dirp->parent != (Dir_t *) NULL) {
  515.     *stackptr++ = dirp->inode;
  516.     dirp = dirp->parent;        /* go to parent */
  517.     }
  518.     /* first get the drive name set up in path */
  519.     bcopy_fn((dirp->name), path, MAXFILENAMELEN);
  520.     ptr = path+1;
  521.     *ptr++ = ':';
  522.  
  523.     while (--stackptr >= stack) {
  524.     *ptr++ = '\\';
  525.     bcopy_fn(InodeTable[*stackptr]->name, ptr, MAXFILENAMELEN);
  526.     while (*ptr) ptr++;
  527.     }
  528.     *ptr++ = '\0';
  529.     return path;
  530. }
  531.  
  532. /*
  533.  *  char *intoname(u_long inode) --
  534.  *      Converts inode to name of file.
  535.  */
  536. char *intoname(inode)
  537.     u_long inode;
  538. {
  539. static char temname[MAXFILENAMELEN];
  540.  
  541.     if (inode > NUMINODES)
  542.         return NULL;
  543.     bcopy_fn((InodeTable[inode])->name, temname, MAXFILENAMELEN);
  544.     return temname;
  545. }    
  546.  
  547. /*
  548.  *  u_long parentinode(u_long inode)
  549.  *      Returns inode number of parent.
  550.  */
  551. u_long parentinode(inode)
  552.      u_long inode;
  553. {
  554.     Dir_t *parent;
  555.     Dir_t *dirp;
  556.  
  557.     if (inode < NUMINODES && (dirp = InodeTable[inode])!=(Dir_t *) NULL) {
  558.     if (dirp->top)
  559.       return inode;
  560.     else if    ((parent = dirp->parent) != (Dir_t *) NULL)
  561.       return (u_long) parent->inode;
  562.     }
  563.     return 0;
  564. }
  565.  
  566. /*
  567.  * inattrset (u_long inode, struct nfsfattr *)
  568.  *    Saves file attributes for a given inode.
  569.  */
  570. struct nfsfattr *inattrset (inode, attr)
  571.      u_long inode;
  572.      struct nfsfattr *attr;
  573. {
  574.     Dir_t *dirp;
  575.  
  576.     if (inode > NUMINODES)
  577.       return (struct nfsfattr *) NULL;
  578.     if ((dirp = InodeTable[inode]) != (Dir_t *) NULL) {
  579.     if (dirp->attr == (Acache_t *) NULL) {
  580.  
  581.         /* Allocate an attributes entry */
  582.         dirp->attr = attrfree;
  583.         if (dirp->attr == NULL) {
  584.  
  585.         /* List is full:  unlink the tail entry from its */
  586.         /* previously associated inode.             */
  587.         dirp->attr = attrcache->prev;
  588.         InodeTable[dirp->attr->inode]->attr = NULL;
  589.         dirp->attr->prev->next = attrcache;
  590.         attrcache->prev = dirp->attr->prev;
  591.         }
  592.         else {
  593.         /* Unlink the entry from the free list.        */
  594.         attrfree = attrfree->next;
  595.         }
  596.  
  597.         /* Add the entry to the head of the active list.    */
  598.         dirp->attr->next = attrcache->next;
  599.         dirp->attr->prev = attrcache;
  600.         attrcache->next->prev = dirp->attr;
  601.         attrcache->next = dirp->attr;
  602.     }
  603.     dirp->attr->inode = (u_short) inode;
  604.     (void) bcopy_nf((char*)attr, (char*)(&dirp->attr->fattr), sizeof (struct nfsfattr));
  605.     }
  606.     else
  607.       return (struct nfsfattr *) NULL;
  608. }
  609.  
  610. /*
  611.  * inattrget (u_long inode, struct nfsfattr *)
  612.  *    Fetches the attributes previously saved within a given inode.
  613.  */
  614. struct nfsfattr *inattrget (inode, attr)
  615.      u_long inode;
  616.      struct nfsfattr *attr;
  617. {
  618.     Dir_t *dirp;
  619.  
  620.     if (inode > NUMINODES)
  621.       return (struct nfsfattr *) NULL;
  622.     if ((dirp = InodeTable[inode]) != (Dir_t *) NULL) {
  623.     if (dirp->attr == (Acache_t *) NULL)
  624.         return (struct nfsfattr *) NULL;
  625.     (void) bcopy_fn((char*)(&dirp->attr->fattr), (char*)attr, sizeof (struct nfsfattr));
  626.  
  627.     /* Move entry to head of attributes cache */
  628.     if (dirp->attr != attrcache->next) {
  629.         dirp->attr->prev->next = dirp->attr->next;
  630.         dirp->attr->next->prev = dirp->attr->prev;
  631.         dirp->attr->next = attrcache->next;
  632.         attrcache->next->prev = dirp->attr;
  633.         attrcache->next = dirp->attr;
  634.         dirp->attr->prev = attrcache;
  635.     }
  636.     return (attr);
  637.     }
  638.     else
  639.       return (struct nfsfattr *) NULL;
  640. }
  641.  
  642. /*
  643.  * ingetfsid (u_long inode)
  644.  *    Fetches the filesystem ID (drive number) of an inode.
  645.  *    Returns -1 if inode is undefined.
  646.  */
  647. int ingetfsid (inode)
  648.      u_long inode;
  649. {
  650.     Dir_t *dirp;
  651.  
  652.     if (inode > NUMINODES || (dirp = InodeTable[inode]) == (Dir_t *) NULL)
  653.       return -1;
  654.     return dirp->fsid;
  655. }
  656.  
  657. /*
  658.  *  u_long newinodeno() --
  659.  *    Returns a new inode number, or aborts if we run out of inodes.
  660.  *    A system cleanup must then occur.
  661.  */
  662. static u_long newinodeno()
  663. {
  664.     if (lastinodeno > NUMINODES) {
  665.     DBGPRT0 (nfserr, "ran out of inodes");
  666.     (void) fprintf(stderr, "server err: out of inodes\n");
  667.     abort();
  668.     }
  669.     return lastinodeno++;
  670. }
  671.  
  672.  
  673. /*
  674.  *  fhandle_t pntofh(char *path) --
  675.  *      Converts path name to file handle.  DOS or UNIX style paths.
  676.  */
  677. fhandle_t pntofh(path)
  678.     char *path;
  679. {
  680.     u_long inodeno;
  681.     fhandle_t fh;
  682.     Dir_t *dirp;
  683.  
  684.     (void) bzero((char*)&fh, sizeof(fhandle_t));
  685.     if ((inodeno = pntoin(path)) == -1)
  686.       inodeno = addpathtodirtree(path);
  687.     dirp = InodeTable[inodeno];
  688.     fh.f.fh_fno = inodeno;
  689.     fh.p.fh_fno = (dirp->top ? inodeno : dirp->parent->inode);
  690.     fh.f.fh_fsid = fh.p.fh_fsid = (dev_t) dirp->fsid;
  691.     fh.f.fh_fgen = (time_t) dirp->gen;
  692.     (void) bcopy_fn(dirp->name, fh.fh_pn, MAXFILENAMELEN);
  693.     
  694.     return fh;
  695. }
  696.  
  697. /*
  698.  * bool_t checkfh (fhandle_t *fhp) --
  699.  *    Checks whether the given fhandle is still valid    (it may not
  700.  *      be if the inode number has been recycled).
  701.  */
  702. bool_t checkfh (fhp)
  703. fhandle_t *fhp;
  704. {
  705.     u_long inode;
  706.     Dir_t *dirp;
  707.  
  708.     inode = fhp->f.fh_fno;
  709.     if (inode > NUMINODES || (dirp = InodeTable[inode]) == NULL)
  710.       return FALSE;
  711.     if (fhp->p.fh_fno != (dirp->top ? inode : dirp->parent->inode) ||
  712.     dirp->fsid != (u_char) fhp->f.fh_fsid ||
  713.     dirp->gen != (u_short) fhp->f.fh_fgen) {
  714.     DBGPRT3 (nfserr, "checkfh:  node %ld gen %d/%d", inode,
  715.          (int) fhp->f.fh_fgen, dirp->gen);
  716.       return FALSE;
  717.     }
  718.     else
  719.       return TRUE;
  720. }
  721.  
  722. #ifdef INODE_DEBUG
  723. main()
  724. {
  725.     char *s, path[MAXPATHNAMELEN];
  726.  
  727.     addpathtodirtree("/c/bin/test");
  728.     addpathtodirtree("/d/stan/src/unfsd");
  729.     addpathtodirtree("/c/bin/testee");
  730.     addpathtodirtree("/d/stan/src/unfsd");
  731.     addpathtodirtree("/d/stan/src/unfsd/tester");
  732.     showtree(RootDir);
  733.     (void) printf("pntoin /d/stan/src is %ld\n", pntoin("/d/stan/src"));
  734.     s = intopn(7, path);
  735.     (void) printf("intopn 7 : %s\n", s);
  736.     (void) free(s);
  737.     s = intopn(7, path);
  738.     (void) printf("intopn 7 : %s\n", s);
  739. }
  740. #endif
  741.